package cn.isjinhao.crws.sql.grammar.create.visitor;

import cn.isjinhao.crws.sql.grammar.CurdStatement;
import cn.isjinhao.crws.sql.grammar.AssignmentList;
import cn.isjinhao.crws.sql.grammar.AssignmentList.Entry;
import cn.isjinhao.crws.sql.grammar.create.InsertVisitor;
import cn.isjinhao.crws.sql.grammar.create.SingleInsertMetaInfo;
import cn.isjinhao.crws.sql.grammar.create.represention.Insert;
import cn.isjinhao.crws.sql.grammar.create.represention.InsertSetRep;
import cn.isjinhao.crws.sql.grammar.create.represention.OnDuplicateKey;
import cn.isjinhao.crws.sql.grammar.create.represention.ValuesRep;
import cn.isjinhao.crws.sql.lexical.token.Token;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author ISJINHAO
 * @Date 2021/4/5 21:47
 */
public class SingleInsertMetaInfoDetector extends InsertVisitor<Set<Token>> {

    private SingleInsertMetaInfo singleInsertMetaInfo;

    @Override
    public Set<Token> visitValuesRep(ValuesRep valuesRep) {
        return new HashSet<>(valuesRep.getColumnList());
    }

    @Override
    public Set<Token> visitSetRep(InsertSetRep insertSetRep) {
        return insertSetRep.getEntryList().accept(this);
    }

    @Override
    public synchronized Set<Token> visitInsert(Insert insert) {
        Set<Token> referenceColumnSet = new HashSet<>();

        init(insert);

        Token tableName = insert.getOperator();
        singleInsertMetaInfo.addReferenceTable(tableName);

        referenceColumnSet.addAll(insert.getSelectStatement().accept(this));
        CurdStatement onDuplicateUpdate = insert.getOnDuplicateUpdate();
        if(onDuplicateUpdate != null) {
            referenceColumnSet.addAll(insert.getOnDuplicateUpdate().accept(this));
        }
        singleInsertMetaInfo.addReferenceColumnSet(referenceColumnSet);

        clear();
        return referenceColumnSet;
    }

    private void init(Insert insert) {
        singleInsertMetaInfo = new SingleInsertMetaInfo(insert);
        insert.setSingleInsertMetaInfo(singleInsertMetaInfo);
    }

    private void clear() {
        singleInsertMetaInfo = null;
    }

    @Override
    public Set<Token> visitEntryList(AssignmentList assignmentList) {
        return assignmentList.getEntryList().stream().map(Entry::getColumnName).collect(Collectors.toSet());
    }

    @Override
    public Set<Token> visitOnDuplicateKey(OnDuplicateKey onDuplicateKey) {
        return onDuplicateKey.getCurdStatement().accept(this);
    }

}
